package com.trussell.genesis.terrainmanipulation;

import com.jme.bounding.CollisionTreeManager;
import com.jme.math.Vector3f;
import com.jmex.terrain.TerrainBlock;

public class TerrainEditUtil {

	public static void raiseLowerTerrain(TerrainBlock tb, Vector3f point,
			int radius, float intensity, float tpf) {

		int x = (int) (point.x / 5);
		int y = (int) (point.z / 5);

		for (int i = (x - radius / 5); i <= (x + radius / 5); i++) {
			for (int j = (y - radius / 5); j <= (y + radius / 5); j++) {
				if (i >= 0 && j >= 0 && i < tb.getSize() && j < tb.getSize()) {
					int difX = Math.abs(x - i);
					int difY = Math.abs(y - j);
					float distance = (float) Math.abs(Math.pow(difX, 2)
							+ Math.pow(difY, 2));

					float valToAdd = intensity / ((distance / (radius)) + 1);
					tb.addHeightMapValue(i, j, valToAdd * tpf);
				}
			}
		}
		tb.updateFromHeightMap();
		CollisionTreeManager.getInstance().updateCollisionTree(tb);
	}

	public static void smoothTerrain(TerrainBlock tb, Vector3f point,
			int radius, float intensity, float tpf) {
		
		int x = (int) (point.x / 5);
		int y = (int) (point.z / 5);

		for (int i = (x - radius / 5); i <= (x + radius / 5); i++) {
			for (int j = (y - radius / 5); j <= (y + radius / 5); j++) {
				if (i >= 0 && j >= 0 && i < tb.getSize() && j < tb.getSize()) {
					float curVal = tb.getHeightMap()[tb.getSize() * j + i];
					float tgtVal = getAverageValue(tb, i, j);
					tb.addHeightMapValue(i, j, (intensity / 2f) * (tgtVal - curVal)
							* tpf);
				}
			}
		}
		tb.updateFromHeightMap();
		CollisionTreeManager.getInstance().updateCollisionTree(tb);
	}

	private static float getAverageValue(TerrainBlock tb, int x, int y) {
		float totalValue = 0;
		int numsIn = 0;

		for (int[] i : getNeighboringLocs(x, y)) {
			if (i != null) {
				if (i[0] >= 0 && i[1] >= 0 && i[0] < tb.getSize()
						&& i[1] < tb.getSize()) {
					numsIn += 1;
					totalValue += tb.getHeightMap()[tb.getSize() * i[1] + i[0]];
				}
			}
		}

		return totalValue / numsIn;
	}

	private static int[][] getNeighboringLocs(int x, int y) {
		int[][] locs = new int[8][2];

		locs[0][0] = x - 1;
		locs[0][1] = y - 1;

		locs[1][0] = x;
		locs[1][1] = y - 1;

		locs[2][0] = x + 1;
		locs[2][1] = y - 1;

		locs[3][0] = x - 1;
		locs[3][1] = y;

		locs[4][0] = x + 1;
		locs[4][1] = y;

		locs[5][0] = x - 1;
		locs[5][1] = y + 1;

		locs[6][0] = x;
		locs[6][1] = y + 1;

		locs[7][0] = x + 1;
		locs[7][1] = y + 1;

		return locs;
	}
}